package xyz.schwi.cels.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSON;
import xyz.schwi.cels.dao.BaseDao;
import xyz.schwi.cels.entity.*;
import xyz.schwi.cels.service.BaseService;
import xyz.schwi.cels.util.BeanFactory;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author schwi
 * @date 2021/9/29 0029  11:16
 */
public class BaseServiceImpl implements BaseService {
    BaseDao baseDao = (BaseDao) BeanFactory.getBean("baseDao");

    @Override
    public PageBean<Word> selectWords(String path, Character firstLitter, int pageSize, int pageNow) throws IOException {
        List<Word> wordList = CollUtil.page(pageNow - 1, pageSize, baseDao.getWordsMap(path).get(firstLitter));
        return new PageBean<>(pageNow - 1, pageSize,
                wordsHasNext(path, firstLitter, pageSize, pageNow - 1),
                wordsPageCount(path, firstLitter, pageSize), wordsCount(path, firstLitter), wordList);
    }

    @Override
    public PageBean<Vocabulary> selectVocabularies(String path, int pageSize, int pageNow) throws IOException {
        List<Vocabulary> vocabularyList = CollUtil.page(pageNow - 1, pageSize, baseDao.selectVocabularies(path));
        return new PageBean<>(pageNow - 1, pageSize,
                vocabulariesHasNext(path, pageSize, pageNow - 1),
                vocabulariesPageCount(path, pageSize), vocabulariesCount(path), vocabularyList);
    }

    @Override
    public PageBean<Base> selectAll(String path, int pageSize, int pageNow) throws IOException {
        List<Base> allList = CollUtil.page(pageNow - 1, pageSize, baseDao.selectError(path));
        return new PageBean<>(pageNow - 1, pageSize,
                errorHasNext(path, pageSize, pageNow - 1),
                errorPageCount(path, pageSize), errorCount(path), allList);
    }

    @Override
    public NewTest newGame() throws IOException {
        List<Word> words = baseDao.selectWords("data\\w.dic");
        List<Vocabulary> vocabularies = baseDao.selectVocabularies("data\\v.dic");
        ArrayList<Base> testList = new ArrayList<>(words);
        testList.addAll(vocabularies);
        Collections.shuffle(testList);
        return new NewTest(0, 0, 0L, 0L, testList);
    }

    @Override
    public NewTest newTest(String wPath, String vPath, int count) throws IOException {
        List<Word> words = baseDao.selectWords(wPath);
        List<Vocabulary> vocabularies = baseDao.selectVocabularies(vPath);
        List<Base> testList = new ArrayList<>();
        int[] random1 = random(wordsCount(wPath));
        int[] random2 = random(vocabulariesCount(vPath));
        for (int i = 0; i < count; i++) {
            Base base;
            if (Math.random() < 0.5) {
                base = words.get(random1[i]);
            } else {
                base = vocabularies.get(random2[i]);
            }
            testList.add(base);
        }
        return new NewTest(0, 0, 0L, 0L, testList);
    }

    @Override
    public NewTest continueGame(String path, String jsonPath) throws IOException {
        List<Base> testList = baseDao.selectHistory(path);
        String json = IoUtil.read(new FileInputStream(jsonPath)).toString();
        NewTest newTest = JSON.parseObject(json, NewTest.class);
        newTest.setTestList(testList);
        return newTest;
    }

    @Override
    public NewTest continueError(String path, String jsonPath) throws IOException {
        List<Base> testList = baseDao.selectError(path);
        String json = IoUtil.read(new FileInputStream(jsonPath)).toString();
        NewTest newTest = JSON.parseObject(json, NewTest.class);
        newTest.setTestList(testList);
        return newTest;
    }

    @Override
    public NewTest readErrTest(String path, String jsonPath, boolean error) throws IOException {
        return error ? continueError(path, jsonPath) : continueGame(path, jsonPath);
    }

    private boolean wordsHasNext(String path, Character firstLitter, int pageSize, int pageNow) throws IOException {
        return wordsPageCount(path, firstLitter, pageSize) > pageNow;
    }

    private boolean vocabulariesHasNext(String path, int pageSize, int pageNow) throws IOException {
        return vocabulariesPageCount(path, pageSize) > pageNow;
    }

    private boolean errorHasNext(String path, int pageSize, int pageNow) throws IOException {
        return errorPageCount(path, pageSize) > pageNow;
    }

    private int wordsCount(String path) throws IOException {
        List<Word> words = baseDao.selectWords(path);
        return words.size();
    }

    private int wordsCount(String path, Character firstLitter) throws IOException {
        List<Word> words = baseDao.selectWords(path).stream().collect(Collectors.groupingBy(Word::getFirstLitter)).get(firstLitter);
        return words.size();
    }

    private int vocabulariesCount(String path) throws IOException {
        List<Vocabulary> vocabularies = baseDao.selectVocabularies(path);
        return vocabularies.size();
    }

    private int errorCount(String path) throws IOException {
        List<Base> error = baseDao.selectError(path);
        return error.size();
    }

    private int wordsPageCount(String path, Character firstLitter, int pageSize) throws IOException {
        List<Word> words = baseDao.selectWords(path).stream().collect(Collectors.groupingBy(Word::getFirstLitter)).get(firstLitter);
        return words.size() / pageSize + (words.size() % pageSize == 0 ? -1 : 0);
    }

    private int vocabulariesPageCount(String path, int pageSize) throws IOException {
        List<Vocabulary> vocabularies = baseDao.selectVocabularies(path);
        return vocabularies.size() / pageSize + (vocabularies.size() % pageSize == 0 ? -1 : 0);
    }

    private int errorPageCount(String path, int pageSize) throws IOException {
        List<Base> error = baseDao.selectError(path);
        return error.size() / pageSize + (error.size() % pageSize == 0 ? -1 : 0);
    }

    private int[] random(int count) {
        int[] num = new int[count];
        for (int i = 0; i < num.length; i++) {
            num[i] = i;
        }
        num = ArrayUtil.shuffle(num);
        return num;
    }
}
